﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Unity;
using Infrastucture;
using TimeSplicerModule.Factories;
using TimeSplicerModule.DomainModels;
using TimeSplicerModule.Security;
using TimeSplicerModule.ViewModels;

namespace TimeSplicerModule.Services
{
    // todo: need to work on this next so that the task form saves propertly

    public interface ITimestampService
    {
        TimestampModel GenerateNext(TaskModel task, TimestampType timestampType);
        TimestampModel UpdateLast(TimestampModel timestamp, TimestampType timestampType);
        TimestampModel Suspend(TaskModel task);
        TimestampModel Complete(TaskModel task);
        List<TimestampModel> GetList(TaskModel task);
    }

    public class TimestampService : ITimestampService
    {
        private readonly IUnityContainer _container;
        private readonly ITimestampFactory _timestampFactory;
        private readonly IProjectFactory _projectFactory;
        private readonly ITaskFactory _taskFactory;


        public TimestampService(IUnityContainer container, ITimestampFactory timestampFactory, IProjectFactory projectFactory, ITaskFactory taskFactory)
        {
            _container = container;
            _timestampFactory = timestampFactory;
            _projectFactory = projectFactory;
            _taskFactory = taskFactory;
        }
        
        // can probably just take in the task and determine the type of timestamp based on the tasks new status
        // nore wokr needs to be done here, should probably work on the taskj first
        public TimestampModel GenerateNext(TaskModel task, TimestampType timestampType)
        {
            var last = getLastTimeStamp(task.TaskGuid);

            // yea should do logic based on the status of that task - so the tasks new status needs to be set first 

            if (last != null)
            {
                // need to 
                last = UpdateLast(last, TimestampType.Suspended);

                // create new
                var stamp = _timestampFactory.CreateNew();
                stamp.TaskGuid = task.TaskGuid;
                stamp.StampNumber = last.StampNumber + 1;
                stamp.StartTime = DateTime.Now;
                stamp.TimestampType = timestampType;

                return _timestampFactory.Upsert(stamp);
            }
            else
            {
                var stamp = new TimestampModel
                {
                    TaskGuid = task.TaskGuid,
                    StampNumber = 1,
                    StartTime = DateTime.Now,
                    TimestampType = timestampType
                };

                return  _timestampFactory.Upsert(stamp);
            }
        }
        public TimestampModel Suspend(TaskModel task)
        {
            var last = getLastTimeStamp(task.TaskGuid);

            if (last != null && last.EndTime.Year < 2000)
            {
                return UpdateLast(last, TimestampType.Suspended);
            }

            return last;
        }
        public TimestampModel Complete(TaskModel task)
        {
            var last = getLastTimeStamp(task.TaskGuid);

            if (last != null)
            {
                if (last.EndTime.Year > 2000)
                {
                    // need to created a completed stamp
                    var stamp = _timestampFactory.CreateNew();
                    stamp.TaskGuid = task.TaskGuid;
                    stamp.StampNumber = last.StampNumber + 1;
                    stamp.StartTime = DateTime.Now;
                    stamp.EndTime = stamp.StartTime;
                    stamp.TimestampType = TimestampType.Completed;

                    // TODO: UPdate TASK, UPDATE PROJECT
                    updateActualHours(stamp.TaskGuid, stamp.Hours);


                    return _timestampFactory.Upsert(stamp);
                }
                else
                {
                    return UpdateLast(last, TimestampType.Completed);
                }
            }


            return last;
        }
        public TimestampModel UpdateLast(TimestampModel timestamp, TimestampType timestampType)
        {
            if (timestamp.TimestampType == TimestampType.Activated)
            {
                timestamp.TimestampType = timestampType;
                timestamp.EndTime = DateTime.Now;

                // UPDATE TASK, PROJECT
                updateActualHours(timestamp.TaskGuid, timestamp.Hours);

                return _timestampFactory.Upsert(timestamp);
            }
            else if (timestamp.TimestampType == TimestampType.Suspended)
            {
                if (timestamp.EndTime == DateTime.MinValue || timestamp.EndTime.Year < 1910) // second check is for when the database min value is 1901
                {
                    // close timestamp
                    timestamp.TimestampType = TimestampType.Completed;
                    timestamp.EndTime = DateTime.Now;
                    
                    // UPDATE TASK, Project
                    updateActualHours(timestamp.TaskGuid, timestamp.Hours);

                    return _timestampFactory.Upsert(timestamp);
                }
                else
                {
                    //// create new timestamp
                    //var stamp = _timestampFactory.CreateNew();
                    //stamp.TaskGuid = timestamp.TaskGuid;
                    //stamp.StampNumber = timestamp.StampNumber + 1;
                    //timestamp.StartTime = DateTime.Now;
                    //timestamp.EndTime = timestamp.StartTime;
                    //timestamp.TimestampType = TimestampType.Completed;

                    //return _timestampFactory.Upsert(stamp);
                }
            }
            else if (timestamp.TimestampType == TimestampType.Completed)
            {
                if (timestamp.EndTime == DateTime.MinValue || timestamp.EndTime.Year < 1910)
                {
                    timestamp.TimestampType = TimestampType.Completed;
                    timestamp.EndTime = DateTime.Now;

                    // UPDATE TASK, PROJECT
                    updateActualHours(timestamp.TaskGuid, timestamp.Hours);

                    return _timestampFactory.Upsert(timestamp);
                }
                else
                {
                    var stamp = new TimestampModel
                    {
                        TaskGuid = timestamp.TaskGuid,
                        StampNumber = timestamp.StampNumber + 1,
                        StartTime = DateTime.Now,
                        EndTime = DateTime.Now,
                        TimestampType = TimestampType.Completed
                    };

                    return _timestampFactory.Upsert(timestamp);
                }
            }
            else if (timestamp.TimestampType == TimestampType.Rollback)
            {
                // not sure if i need to do anything with this yet
                throw new NotImplementedException();
            }

            return timestamp;
        }


        // TODO: Method that updates tasks and project actual Hours
        private void updateActualHours(Guid taskGuid, double hours)
        {
            var task = _taskFactory.Get(x => x.TaskGuid == taskGuid);

            if (task != null)
            {
                task.ActualHours += hours;
                task.LastWorked = DateTime.Now;
                _taskFactory.Upsert(task);

                var project = _projectFactory.Get(x => x.ProjectGuid == task.ProjectGuid);

                if (project != null)
                {
                    project.ActualHours += hours;
                    _projectFactory.Upsert(project);
                }
            }
        }



        // helpers
        private TimestampModel getLastTimeStamp(Guid taskGuid)
        {
            return _timestampFactory.GetList().Where(x => x.TaskGuid == taskGuid).OrderByDescending(o => o.StampNumber).FirstOrDefault();
        }


        public List<TimestampModel> GetList(TaskModel task)
        {
            return _timestampFactory.GetList(x => x.TaskGuid == task.TaskGuid).OrderBy(o => o.StampNumber).ToList();
        }
    }
}
